﻿<!DOCTYPE HTML>
<html lang="zh">
<head>
<title>#HotIf - 语法 &amp; 使用 | AutoHotkey v2</title>
<meta name="description" content="The #HotIf directive creates context-sensitive hotkeys and hotstrings. Such hotkeys perform a different action (or none at all) depending on any condition (an expression)." />
<meta name="ahk:equiv-v1" content="lib/_If.htm" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link href="../static/theme.css" rel="stylesheet" type="text/css" />
<script src="../static/content.js" type="text/javascript"></script>
</head>
<body>


<h1>#HotIf</h1>

<p>创建上下文相关的<a href="../Hotkeys.htm">热键</a>和<a href="../Hotstrings.htm">热字串</a>. 这样的热键会根据表达式的结果执行不同的操作(或什么都不做).</p>

<pre class="Syntax"><span class="func">#HotIf</span> <span class="optional">Expression</span></pre>
<h2 id="Parameters">参数</h2>
<dl>

  <dt>Expression</dt>
  <dd>
    <p>类型: <a href="../Concepts.htm#boolean">布尔值</a></p>
    <p>如果省略. 则随后创建的热键和热字串与上下文不相关. 否则, 请指定任何有效的<a href="../Variables.htm#Expressions">表达式</a>. 这将成为隐式函数的返回值, 该函数有一个参数(<a href="../Hotkeys.htm#ThisHotkey">ThisHotkey</a>). 该函数不能直接修改全局变量(因为它通常是<a href="../Functions.htm#AssumeLocal">假定-局部</a>函数, 而且不能包含声明), 但可以调用其他函数来修改全局变量.</p>
  </dd>

</dl>

<h2 id="howto">基本操作</h2>
<p>#HotIf 指令设置表达式, 随后创建的热键将使用该表达式来确定是否应激活它们. 当按下键, 鼠标按钮或组合键, 或者在程序需要知道热键是否处于活动状态时, 将对该表达式求值.</p>
<p>要生成上下文敏感的<a href="../Hotkeys.htm">热键</a>和<a href="../Hotstrings.htm">热字串</a>, 只需在它们前面加上 #HotIf 指令. 例如:</p>
<pre>#HotIf WinActive("ahk_class Notepad") or WinActive(MyWindowTitle)
#Space::MsgBox "You pressed Win+Spacebar in Notepad or " MyWindowTitle</pre>
<p>#HotIf 指令是与位置相关的: 它会影响脚本中在它后面的所有热键和热字串, 直到下一个 #HotIf 指令.</p>
<p class="warning"><strong>注意:</strong> 与 <a href="If.htm">if 语句</a>不同, 大括号对 #HotIf 指令无效.</p>
<p>要关闭热键的上下文相关性, 请指定不带任何表达式的 #HotIf 指令. 例如:</p>
<pre>#HotIf</pre>
<p>和其他指令一样, #HotIf 不能有条件地执行.</p>
<p>当通过 #HotIf 禁用鼠标或键盘热键时, 它会执行其原来的功能; 也就是说, 它传递到活动窗口, 就好像不存在热键一样. 但有一个例外: 控制器热键: 尽管 #HotIf 有效, 它始终不会阻止其他程序看到控制器按钮按下.</p>
<p>#HotIf 也可以用来改变普通按键(例如 <kbd>Enter</kbd> 或 <kbd>Space</kbd>) 的行为. 当某个特定窗口忽略该键或执行某些您认为不需要的操作时, 这是非常有用的. 例如:</p>
<pre>#HotIf WinActive("Reminders ahk_class #32770")  <em>; Outlook 中的 "reminders" 窗口.</em>
Enter::Send "!o"  <em>; 按下 "Enter" 打开 reminder, 而不是 snoozing.</em>
#HotIf</pre>

<h2 id="variant">变体(副本) 热键</h2>
<p>一个特定的<a href="../Hotkeys.htm">热键</a>或<a href="../Hotstrings.htm">热字串</a>在脚本中可以被创建多次, 如果每个定义有不同的 HotIf 条件. 这被称为 <em>热键变体</em>. 例如:</p>
<pre>#HotIf <a href="WinActive.htm">WinActive</a>("ahk_class Notepad")
^!c::MsgBox "You pressed Control+Alt+C in Notepad."
#HotIf WinActive("ahk_class WordPadClass")
^!c::MsgBox "You pressed Control+Alt+C in WordPad."
#HotIf
^!c::MsgBox "You pressed Control+Alt+C in a window other than Notepad/WordPad."</pre>
<p>如果有多个变体符合触发条件, 那么仅触发最早创建的那个. 这种情况的例外是全局变体(不带 HotIf 条件的那个): 它的优先级总是最低的, 仅当其他变体都不触发时它才会被触发(此例外不适用<a href="../Hotstrings.htm">热字串</a>).</p>
<p>创建重复热键时, <a href="../Hotkeys.htm#Symbols">修饰符</a>的顺序(如 <code>^!+#</code>) 没有关系. 例如, <code>^!c</code> 等同于 <code>!^c</code>. 但是, 按键必须拼写一致. 例如, 为了这个目的时, <em>Esc</em> 不同于 <em>Escape</em>(尽管大小写无关). 最后, 任何带有<a href="../Hotkeys.htm#wildcard">通配符前缀(*)</a> 的热键和不带通配符的热键是完全独立的; 例如, <code>*F1</code> 和 <code>F1</code> 都可以有他们各自的变体.</p>
<p><a href="GroupAdd.htm">窗口组</a>可以用来使热键为一组窗口执行. 例如:</p>
<pre>
GroupAdd "MyGroup", "ahk_class Notepad"
GroupAdd "MyGroup", "ahk_class WordPadClass"

#HotIf WinActive("ahk_group MyGroup")
#z::MsgBox "You pressed Win+Z in either Notepad or WordPad."
</pre>
</p>
<p>另外, 也可以通过 <code>#HotIf WinActive("ahk_group MyGroup")</code> 来使用<a href="GroupAdd.htm">窗口组</a>.</p>
<p>要动态地创建热键变体(当脚本运行时), 请参阅 <a href="HotIf.htm">HotIf</a>.</p>

<h2 id="expression-evaluation">表达式的计算</h2>
<p>当热键, 鼠标或控制器按钮组合被按下时, #HotIf 表达式被计算以确定热键是否应该被激活.</p>
<p class="warning"><strong>注意:</strong> 脚本不应假定表达式只在按键被按下时才被计算(见下文).</p>
<p>只要程序需要知道热键是否被激活, 表达式也可以被计算. 例如, #HotIf 表达式作用于一个自定义组合热键(如 <code>a &amp; b::</code>), 当按下前缀按键(这个例子中的 <code>a</code>) 时, 表达式将会计算一次, 计算结果将决定组合热键是否起作用.</p>
<p class="warning" id="lag"><strong>注意:</strong> 使用 #HotIf 时, 在脚本无响应时可能会导致输入滞后或破坏热键(见下文).</p>
<p>对于 #HotIf 指令还有一些注意事项:</p>
<ul>
  <li>键盘或鼠标输入通常被缓冲(延迟), 直到表达式计算完成或<a href="_HotIfTimeout.htm">超时</a>.</li>
  <li>表达式的计算只能由脚本的主线程(在操作系统级别, 而不是<a href="../misc/Threads.htm">准线程</a>), 而不是由键盘/鼠标钩子直接执行. 如果脚本忙或者没有响应, 比如在进程中出现了 FileCopy, 那么表达式的计算就会被延迟, 并且可能会超时.</li>
  <li>如果达到<a href="_HotIfTimeout.htm#LowLevelHooksTimeout">系统定义的超时</a>, 系统可能会停止通知脚本键盘或鼠标输入(有关详情, 请参阅 #HotIfTimeout).</li>
  <li>在计算表达式时, 发送击键或鼠标单击(例如, 从它调用的函数中), 可能会导致并发, 应该避免.</li>
</ul>
<p><a href="../Hotkeys.htm#ThisHotkey">ThisHotkey</a>, <a href="../Variables.htm#ThisHotkey">A_ThisHotkey</a> 和 <a href="../Variables.htm#TimeSinceThisHotkey">A_TimeSinceThisHotkey</a> 是基于当前正在计算的 #HotIf 表达式的热键来设置的.</p>
<p><a href="../Variables.htm#PriorHotkey">A_PriorHotkey</a> 和 <a href="../Variables.htm#TimeSincePriorHotkey">A_TimeSincePriorHotkey</a> 暂时包含对应 "This" 变量的前一个值.</p>

<h2 id="optimization">优化</h2>
<p>为避免对 <a href="WinActive.htm">WinActive</a> 或 <a href="WinExist.htm">WinExist</a> 的简单调用而去计算表达式, 对 #HotIf 进行了优化, 从而降低了在这种情况下出现<a href="#lag">滞后</a>或其他问题的风险. 具体来说:</p>
<ul>
  <li>表达式必须包含一次对 <a href="WinExist.htm">WinExist</a> 或 <a href="WinActive.htm">WinActive</a> 的调用.</li>
  <li>每个参数必须是一个单引号的字符串, 并且不得使用超过两个参数.</li>
  <li>结果可以用 <code>not</code> 或 <code>!</code> 进行反转, 但不能使用其他运算符.</li>
  <li>当表达式被预编译时, 空白和括号会被完全处理, 因此不会影响这种优化.</li>
</ul>
<p>如果表达式符合这些条件, 则直接由程序计算, 不会出现在 <a href="ListLines.htm">ListLines</a> 中.</p>
<p>在使用<a href="Hotkey.htm">热键</a>函数修改现有的热键变体之前, 通常 <a href="HotIf.htm">HotIf</a> 函数必须与原始表达式文本一起使用. 然而, 第一个具有给定组合条件的唯一表达式也可以被该条件引用. 例如:</p>
<pre>
HotIfWinExist "ahk_class Notepad"
Hotkey "#n", "Off"  <em>; 关闭热键.</em>
HotIf 'WinExist("ahk_class Notepad")'
Hotkey "#n", "On"   <em>; 打开同一个热键.</em>

#HotIf WinExist("ahk_class Notepad")
#n::WinActivate
</pre>
<p>注意, 任何变量的使用都会取消表达式的资格. 如果在创建热键后, 变量的值永远不会改变, 有两种策略可以最大限度地降低 #HotIf 的滞后风险或其他固有问题:</p>
<ul>
  <li>使用 <code class="no-highlight"><a href="HotIf.htm#IfWin">HotIfWin...</a> MyTitleVar</code> 来设置条件和 <code><a href="Hotkey.htm">Hotkey</a> KeyName, Label</code> 来创建热键变体.</li>
  <li>使用常量表达式, 如 <code>#HotIf WinActive("ahk_group MyGroup")</code> 和并在脚本的其他地方使用 <code><a href="GroupAdd.htm">GroupAdd</a> "MyGroup", MyTitleVar</code> 定义窗口组.</li>
</ul>

<h2 id="general-remarks">备注</h2>
<p>适当的时候, #HotIf 也会将前缀键恢复到它们的原生功能(如 <code>a &amp; b</code>, <a href="../Hotkeys.htm#prefix">前缀键</a>是热键中的 <kbd>A</kbd>). 当给定的前缀键没有启用热键时, 就会发生这种情况.</p>
<p>当 Gosub 或 Goto 用于跳转到一个热键或热字符串标签时, 它会跳转到最接近脚本顶部的变体.</p>
<p>当前被 #HotIf 禁用的热键, 它的按键或鼠标按钮在 <a href="KeyHistory.htm">KeyHistory</a> 的 "Type" 列中显示时会带有 "#" 字符. 这可以帮助<a href="../Scripts.htm#debug">调试脚本</a>.</p>
<p><a href="../Hotkeys.htm#alttab">Alt-tab 热键</a>不受 #HotIf 影响: 它们对所有窗口都有效.</p>
<p><a href="../misc/WinTitle.htm#LastFoundWindow">最后找到的窗口</a>可以通过 #HotIf 来设置. 例如:</p>
<pre>#HotIf <a href="WinExist.htm">WinExist</a>("ahk_class Notepad")
#n::<a href="WinActivate.htm">WinActivate</a>  <em>; 激活由 WinExist() 找到的窗口.</em></pre>

<h2 id="Related">相关</h2>
<p><a href="_HotIfTimeout.htm">#HotIfTimeout</a> 可以用于覆盖默认的超时时间值.</p>
<p><a href="Hotkey.htm">Hotkey 函数</a>, <a href="../Hotkeys.htm">热键</a>, <a href="../Hotstrings.htm">热字串</a>, <a href="Suspend.htm">Suspend</a>, <a href="WinActive.htm">WinActive</a>, <a href="WinExist.htm">WinExist</a>, <a href="SetTitleMatchMode.htm">SetTitleMatchMode</a>, <a href="DetectHiddenWindows.htm">DetectHiddenWindows</a></p>

<h2 id="Examples">示例</h2>
<div class="ex" id="ExBasic">
<p><a class="ex_number" href="#ExBasic"></a> 创建只有在记事本处于活动状态时才生效的两个热键和一个热字符串, 而一个热键则适用于除记事本以外的任何窗口.</p>
<pre>#HotIf WinActive("ahk_class Notepad")
^!a::MsgBox "You pressed Ctrl-Alt-A while Notepad is active."
#c::MsgBox "You pressed Win-C while Notepad is active."
::btw::This replacement text for "btw" will occur only in Notepad.
#HotIf
#c::MsgBox "You pressed Win-C in a window other than Notepad."</pre>
</div>

<div class="ex" id="ExVolume">
<p><a class="ex_number" href="#ExVolume"></a> 允许在任务栏上滚动鼠标滚轮来调节音量.</p>
<pre>
#HotIf MouseIsOver("ahk_class Shell_TrayWnd")
WheelUp::Send "{Volume_Up}"
WheelDown::Send "{Volume_Down}"

MouseIsOver(WinTitle) {
    MouseGetPos ,, &amp;Win
    return WinExist(WinTitle " ahk_id " Win)
}
</pre>
</div>

<div class="ex" id="ExWordDelete">
<p><a class="ex_number" href="#ExWordDelete"></a> 在所有的编辑控件中的轻松删除单词的快捷键.</p>
<pre>
#HotIf ActiveControlIsOfClass("Edit")
^BS::Send "^+{Left}{Del}"
^Del::Send "^+{Right}{Del}"

ActiveControlIsOfClass(Cls) {
    FocusedControl := 0
    try FocusedControl := ControlGetFocus("A")
    FocusedControlClass := ""
    try FocusedControlClass := WinGetClass(FocusedControl)
    return (FocusedControlClass=Cls)
}
</pre>
</div>

<div class="ex" id="ExContextInsens">
<p><a class="ex_number" href="#ExContextInsens"></a> 与上下文不相关的热键.</p>
<pre>
#HotIf
Esc::ExitApp
</pre>
</div>

<div class="ex" id="ExDynamic">
<p><a class="ex_number" href="#ExDynamic"></a> 动态热键. 这个例子在运行前需要整和<a href="#ExVolume">示例 #2</a>.</p>
<pre>
NumpadAdd::
{
    static toggle := false
    HotIf 'MouseIsOver("ahk_class Shell_TrayWnd")'
    if (toggle := !toggle)
        Hotkey "WheelUp", DoubleUp
    else
        Hotkey "WheelUp", "WheelUp"
    return
    ; 嵌套函数:
    DoubleUp(ThisHotkey) =&gt; Send("{Volume_Up 2}")
}
</pre>
</div>

</body>
</html>